package com.lzs.common.utils.wechat;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.lzs.common.properties.BaseWeixinProperties;
import com.lzs.common.properties.WeixinProperties;
import com.lzs.common.utils.MD5;
import com.lzs.common.utils.UUIDUtils;
import com.lzs.common.utils.wechat.wechatpay.WechatConfig;
import com.lzs.common.utils.wechat.wechatpay.WxPayUtil;
import com.lzs.common.utils.wechat.wechatpay.XmlUtil;
import com.lzs.common.utils.wechat.weixin.WeChatPayBean;
import com.lzs.common.utils.wechat.weixin.WechatCompanyTransferPersonApiResult;
import com.lzs.common.vo.CommonResult;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.Md5Crypt;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
@EnableConfigurationProperties(WeixinProperties.class)
public class WeChatUtil {

    @Autowired
    private WeixinProperties weixinProperties;

    public CommonResult<Map<String,String>> uniformOrderApp(BigDecimal totalAmount, String orderNo, String subject, String attach){
        BaseWeixinProperties student = weixinProperties.getMiniapp();
        String appid = student.getAppid();
        String merchantId = weixinProperties.getMchid();
        String appUniformUrl = weixinProperties.getAppUniformUrl();
        String signKey = weixinProperties.getSignKey();
        String apiV3Key = weixinProperties.getApiV3Key();
        String merchantPrivateKey = weixinProperties.getMerchantPrivateKey();
        String merchantSerialNumber = weixinProperties.getMerchantSerialNumber();
        String notifyUrl = weixinProperties.getNotifyUrl();
        try {
            PrivateKey privateKey = PemUtil.loadPrivateKey(
                    new FileInputStream(merchantPrivateKey));
            AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                    new WechatPay2Credentials(merchantId, new PrivateKeySigner(merchantSerialNumber, privateKey)),
                    apiV3Key.getBytes(StandardCharsets.UTF_8));
            WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                    .withMerchant(merchantId, merchantSerialNumber, privateKey)
                    .withValidator(new WechatPay2Validator(verifier));
            HttpClient httpClient = builder.build();
            HttpPost httpPost = new HttpPost(appUniformUrl);
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type","application/json; charset=utf-8");

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();

            ObjectNode rootNode = objectMapper.createObjectNode();
            rootNode.put("mchid",merchantId)
                    .put("appid", appid)
                    .put("description", subject)
                    .put("attach",attach)
                    .put("notify_url", notifyUrl)
                    .put("out_trade_no", orderNo);
            rootNode.putObject("amount")
                    .put("total", totalAmount.multiply(new BigDecimal("100")).longValue());
            log.info("微信支付参数:mchid[{}],appid[{}],description[{}],attach[{}],notify_url[{}],out_trade_no[{}],totalAmount[{}]元",
                    merchantId,appid,subject,attach,notifyUrl,orderNo,totalAmount);
            objectMapper.writeValue(bos, rootNode);

            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            String bodyAsString = EntityUtils.toString(response.getEntity());
            log.info("微信支付返回结果:{}",bodyAsString);
            JSONObject object = JSONObject.parseObject(bodyAsString);
            Map<String,String> map = new HashMap<>();
            String prepay_id = object.getString("prepay_id");
            if (!StringUtils.hasText(prepay_id)){
                return CommonResult.Err(object.getString("message"));
            }
            String timeStamp = String.valueOf(new Date().getTime() / 1000);

            String randomStr = UUIDUtils.generateUUID();
            map.put("appid", appid);
            map.put("partnerid",merchantId);
            map.put("prepayid",prepay_id);
            map.put("package", "Sign=WXPay");
            map.put("noncestr", randomStr);
            map.put("timestamp",timeStamp);
            String data = appid + "\n" + timeStamp + "\n" + randomStr + "\n" + prepay_id + "\n";
            String paySign = encryptByPrivateKey(data, privateKey);
            map.put("sign", paySign);
//            map.put("sign", WxPayUtil.generateSignature(map,signKey));
            map.put("orderNo",orderNo);
            return CommonResult.OK(map);
        }catch (Exception e){
            log.error("微信支付异常",e);
            return CommonResult.Err("网络异常");
        }
    }

    /**
     * 二维码支付
     * @param totalAmount
     * @param orderNo
     * @param subject
     * @param attach
     * @return
     */
    public CommonResult<Map<String,String>> uniformOrderByQR(BigDecimal totalAmount, String orderNo, String subject, String attach){
        BaseWeixinProperties student = weixinProperties.getMiniapp();
        String appid = student.getAppid();
        String merchantId = weixinProperties.getMchid();
        String appUniformUrl = weixinProperties.getQrCodeUniformUrl();
        String signKey = weixinProperties.getSignKey();
        String apiV3Key = weixinProperties.getApiV3Key();
        String merchantPrivateKey = weixinProperties.getMerchantPrivateKey();
        String merchantSerialNumber = weixinProperties.getMerchantSerialNumber();
        String notifyUrl = weixinProperties.getNotifyUrl();
        try {
            PrivateKey privateKey = PemUtil.loadPrivateKey(
                    new FileInputStream(merchantPrivateKey));
            AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                    new WechatPay2Credentials(merchantId, new PrivateKeySigner(merchantSerialNumber, privateKey)),
                    apiV3Key.getBytes(StandardCharsets.UTF_8));
            WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                    .withMerchant(merchantId, merchantSerialNumber, privateKey)
                    .withValidator(new WechatPay2Validator(verifier));
            HttpClient httpClient = builder.build();
            HttpPost httpPost = new HttpPost(appUniformUrl);
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type","application/json; charset=utf-8");

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();

            ObjectNode rootNode = objectMapper.createObjectNode();
            rootNode.put("mchid",merchantId)
                    .put("appid", appid)
                    .put("description", subject)
                    .put("attach",attach)
                    .put("notify_url", notifyUrl)
                    .put("out_trade_no", orderNo);
            rootNode.putObject("amount")
                    .put("total", totalAmount.multiply(new BigDecimal("100")).longValue());
            log.info("微信支付参数:mchid[{}],appid[{}],description[{}],attach[{}],notify_url[{}],out_trade_no[{}],totalAmount[{}]元",
                    merchantId,appid,subject,attach,notifyUrl,orderNo,totalAmount);
            objectMapper.writeValue(bos, rootNode);

            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            String bodyAsString = EntityUtils.toString(response.getEntity());
//            String bodyAsString="{\"code_url\":\"111111\"}";
            log.info("微信支付返回结果:{}",bodyAsString);
            JSONObject object = JSONObject.parseObject(bodyAsString);
            Map<String,String> map = new HashMap<>();
            String code_url = object.getString("code_url");
            if (!StringUtils.hasText(code_url)){
                return CommonResult.Err(object.getString("message"));
            }
//            String timeStamp = String.valueOf(new Date().getTime() / 1000);
//            String randomStr = CommonUtil.getUUID();
//            map.put("appid", appid);
//            map.put("partnerid",merchantId);
            map.put("code_url",code_url);
//            map.put("package", "Sign=WXPay");
//            map.put("noncestr", randomStr);
//            map.put("timestamp",timeStamp);
//            map.put("sign", WxPayUtil.generateSignature(map,signKey));
            map.put("payOrderNo",orderNo);
            return CommonResult.OK(map);
        }catch (Exception e){
            log.error("微信支付异常",e);
            return CommonResult.Err("网络异常");
        }
    }

    public CommonResult<Map<String,String>> uniformOrderByH5(BigDecimal totalAmount, String orderNo, String subject, String attach, String ipAddr){
        BaseWeixinProperties student = weixinProperties.getMiniapp();
        String appid = student.getAppid();
        String merchantId = weixinProperties.getMchid();
        String h5UniformUrl = weixinProperties.getH5UniformUrl();
        String signKey = weixinProperties.getSignKey();
        String apiV3Key = weixinProperties.getApiV3Key();
        String merchantPrivateKey = weixinProperties.getMerchantPrivateKey();
        String merchantSerialNumber = weixinProperties.getMerchantSerialNumber();
        String notifyUrl = weixinProperties.getNotifyUrl();
        try {
            PrivateKey privateKey = PemUtil.loadPrivateKey(
                    new FileInputStream(merchantPrivateKey));
            AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                    new WechatPay2Credentials(merchantId, new PrivateKeySigner(merchantSerialNumber, privateKey)),
                    apiV3Key.getBytes(StandardCharsets.UTF_8));
            WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                    .withMerchant(merchantId, merchantSerialNumber, privateKey)
                    .withValidator(new WechatPay2Validator(verifier));
            HttpClient httpClient = builder.build();
            HttpPost httpPost = new HttpPost(h5UniformUrl);
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type","application/json; charset=utf-8");

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();
            ObjectNode rootNode = objectMapper.createObjectNode();
            rootNode.put("appid", appid)
                    .put("mchid",merchantId)
                    .put("description", subject)
                    .put("out_trade_no", orderNo)
                    .put("attach",attach)
                    .put("notify_url", notifyUrl);
            rootNode.putObject("amount")
                    .put("total", totalAmount.multiply(new BigDecimal("100")).longValue());
            rootNode.putObject("scene_info")
                    .put("payer_client_ip", StringUtils.isEmpty(ipAddr)?"127.0.0.1":ipAddr)
                    .putObject("h5_info")
                    .put("type","Wap");
            log.info("微信支付参数:mchid[{}],appid[{}],description[{}],attach[{}],notify_url[{}],out_trade_no[{}],totalAmount[{}]元",
                    merchantId,appid,subject,attach,notifyUrl,orderNo,totalAmount);
            objectMapper.writeValue(bos, rootNode);

            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            String bodyAsString = EntityUtils.toString(response.getEntity());
            log.info("微信支付返回结果:{}",bodyAsString);
            JSONObject object = JSONObject.parseObject(bodyAsString);
            Map<String,String> map = new HashMap<>();
            String h5_url = object.getString("h5_url");
            if (!StringUtils.hasText(h5_url)){
                return CommonResult.Err(object.getString("message"));
            }
//            String timeStamp = String.valueOf(new Date().getTime() / 1000);
//            String randomStr = UUIDUtils.generateUUID();
//            map.put("appId", appid);
//            map.put("timeStamp",timeStamp);
//            map.put("nonceStr", randomStr);
            map.put("h5_url", h5_url);
//            map.put("paySign", WxPayUtil.generateSignature(map,signKey, SignType.HMACSHA256));
//            map.put("partnerid",merchantId);
//            map.put("signType","RSA");
            map.put("orderNo",orderNo);
            return CommonResult.OK(map);
        }catch (Exception e){
            log.error("微信H5支付异常",e);
            return CommonResult.Err("网络异常");
        }
    }


    public CommonResult<Map<String, String>> uniformOrderByJsapi(BigDecimal totalAmount, String orderNo, String subject,
                                                                 String openId,String appid,String attach) {
        String merchantId = weixinProperties.getMchid();
        String appUniformUrl = weixinProperties.getJsapiUniformUrl();
        String signKey = weixinProperties.getSignKey();
        String apiV3Key = weixinProperties.getApiV3Key();
        String merchantPrivateKey = weixinProperties.getMerchantPrivateKey();
        String merchantSerialNumber = weixinProperties.getMerchantSerialNumber();
        String notifyUrl = weixinProperties.getNotifyUrl();
        try {
            PrivateKey privateKey = PemUtil.loadPrivateKey(
                    new FileInputStream(merchantPrivateKey));
            AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                    new WechatPay2Credentials(merchantId, new PrivateKeySigner(merchantSerialNumber, privateKey)),
                    apiV3Key.getBytes(StandardCharsets.UTF_8));
            WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                    .withMerchant(merchantId, merchantSerialNumber, privateKey)
                    .withValidator(new WechatPay2Validator(verifier));
            HttpClient httpClient = builder.build();
            HttpPost httpPost = new HttpPost(appUniformUrl);
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type","application/json; charset=utf-8");

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();

            ObjectNode rootNode = objectMapper.createObjectNode();
            rootNode.put("mchid",merchantId)
                    .put("appid", appid)
                    .put("description", subject)
                    .put("attach",attach)
                    .put("notify_url", notifyUrl)
                    .put("out_trade_no", orderNo);
            rootNode.putObject("amount")
                    .put("total", totalAmount.multiply(new BigDecimal("100")).longValue());
            rootNode.putObject("payer")
                    .put("openid", openId);
            log.info("微信支付参数:mchid[{}],appid[{}],description[{}],attach[{}],notify_url[{}],out_trade_no[{}],totalAmount[{}]元",
                    merchantId,appid,subject,attach,notifyUrl,orderNo,totalAmount);
            objectMapper.writeValue(bos, rootNode);

            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            String bodyAsString = EntityUtils.toString(response.getEntity());
            log.info("微信支付返回结果:{}",bodyAsString);
            JSONObject object = JSONObject.parseObject(bodyAsString);
            Map<String,String> map = new HashMap<>();
            String prepay_id = object.getString("prepay_id");
            if (!StringUtils.hasText(prepay_id)){
                return CommonResult.Err(object.getString("message"));
            }
            String timeStamp = String.valueOf(new Date().getTime() / 1000);
            String randomStr = UUIDUtils.generateUUID();
            map.put("appId", appid);
            map.put("timeStamp",timeStamp);
            map.put("nonceStr", randomStr);
            map.put("package", "prepay_id="+prepay_id);
            String data= appid+"\n"+timeStamp+"\n"+randomStr+"\n"+ "prepay_id="+prepay_id+"\n";
//            String sign = WxPayUtil.HMACSHA256(data, signKey);
            log.info("参与签名:{}",data);
            String paySign = encryptByPrivateKey(data, privateKey);
            map.put("paySign", paySign);
            map.put("orderNo",orderNo);
            map.put("signType","RSA");
            return CommonResult.OK(map);
        }catch (Exception e){
            log.error("微信jsapi支付异常",e);
            return CommonResult.Err("网络异常");
        }
    }
    public CommonResult<WeChatPayBean>  weixinNotify(HttpServletRequest request) {
        String apiV3Key = weixinProperties.getApiV3Key();
        try {
            String wxSignature = request.getHeader("Wechatpay-Signature");
            String headerSerial = request.getHeader("Wechatpay-Serial");
            String headerTimestamp = request.getHeader("Wechatpay-Timestamp");
            String headerNonce = request.getHeader("Wechatpay-Nonce");
            ServletInputStream inputStream = request.getInputStream();
            String collect = new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.joining(System.lineSeparator()));
            log.info("微信支付回调通知:{} ", collect);
            log.info("微信支付回调通知 wxSignature:{},serial:{},timestamp:{},headerNonce:{}",wxSignature,headerSerial,headerTimestamp,headerNonce);
            boolean verifySign = verifySign(headerTimestamp, headerNonce, collect, headerSerial, wxSignature);
            if (!verifySign){
                return CommonResult.Err("验签失败");
            }
            String decrypt = decryptData(collect, apiV3Key);
            JSONObject object = JSONObject.parseObject(decrypt);
            WeChatPayBean weChatPayBean = JSONObject.toJavaObject(object, WeChatPayBean.class);

            return CommonResult.OK(weChatPayBean);
        } catch (IOException e) {
            log.error("微信支付回调异常",e);
            return CommonResult.Err("网络异常");
        }
    }
   /* public ResponseBean<WeChatRefundBean>  weixinRefundNotify(HttpServletRequest request) {
        ResponseBean<WeChatRefundBean> commonResult = ResponseBean.OK();
        String apiV3Key = weixinProperties.getApiV3Key();
        try {
            String wxSignature = request.getHeader("Wechatpay-Signature");
            String headerSerial = request.getHeader("Wechatpay-Serial");
            String headerTimestamp = request.getHeader("Wechatpay-Timestamp");
            String headerNonce = request.getHeader("Wechatpay-Nonce");
            ServletInputStream inputStream = request.getInputStream();
            String collect = new BufferedReader(new InputStreamReader(inputStream)).lines().collect(Collectors.joining(System.lineSeparator()));
            log.info("微信退款回调通知:{} ", collect);
            log.info("微信退款回调通知 wxSignature:{},serial:{},timestamp:{},headerNonce:{}",wxSignature,headerSerial,headerTimestamp,headerNonce);
            boolean verifySign = verifySign(headerTimestamp, headerNonce, collect, headerSerial, wxSignature);
            if (!verifySign){
                commonResult.setCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
                commonResult.setMsg("验签失败");
                return commonResult;
            }
            JSONObject data = JSONObject.parseObject(collect);
            String event_type = data.getString("event_type");
            if ("REFUND.SUCCESS".equals(event_type)){
                String decrypt = decryptData(collect, apiV3Key);
                JSONObject object = JSONObject.parseObject(decrypt);
                WeChatRefundBean weChatPayBean = JSONObject.toJavaObject(object, WeChatRefundBean.class);
                commonResult.setObj(weChatPayBean);
            }else if ("REFUND.ABNORMAL".equals(event_type)){
                commonResult.setCode(HttpStatus.SC_ACCEPTED);
                commonResult.setMsg("退款异常，请手工处理");
                return commonResult;
            }else if ("REFUND.CLOSED".equals(event_type)){
                commonResult.setCode(HttpStatus.SC_ACCEPTED);
                commonResult.setMsg("退款关闭");
                return commonResult;
            }

        } catch (IOException e) {
            log.error("微信退款回调异常",e);
            commonResult.setCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
            commonResult.setMsg("网络异常");
        }
        return commonResult;
    }*/

    /**
     * 微信退款
     * @param refundNo 退款单号
     * @param refundAmount 退款金额
     * @param totalAmount 订单支付金额
     * @param channelOrderNo 微信方支付订单号
     * @param refundReason 退款原因
     * @return
     */
    public CommonResult<Map<String,String>> refund(String refundNo,BigDecimal refundAmount,BigDecimal totalAmount,String channelOrderNo,String refundReason){
        BaseWeixinProperties student = weixinProperties.getMiniapp();
        String appid = student.getAppid();
        String merchantId = weixinProperties.getMchid();
        String apiV3Key = weixinProperties.getApiV3Key();
        String merchantPrivateKey = weixinProperties.getMerchantPrivateKey();
        String merchantSerialNumber = weixinProperties.getMerchantSerialNumber();
        String refundNotifyUrl = weixinProperties.getRefundNotifyUrl();

        try {
            PrivateKey privateKey = PemUtil.loadPrivateKey(
                    new FileInputStream(merchantPrivateKey));
            AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                    new WechatPay2Credentials(merchantId, new PrivateKeySigner(merchantSerialNumber, privateKey)),
                    apiV3Key.getBytes(StandardCharsets.UTF_8));
            WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                    .withMerchant(merchantId, merchantSerialNumber, privateKey)
                    .withValidator(new WechatPay2Validator(verifier));
            HttpClient httpClient = builder.build();
            HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds");
            httpPost.addHeader("Accept", "application/json");
            httpPost.addHeader("Content-type","application/json; charset=utf-8");

            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectMapper objectMapper = new ObjectMapper();

            ObjectNode rootNode = objectMapper.createObjectNode();
            rootNode.put("transaction_id", channelOrderNo)
                    .put("out_refund_no",refundNo)
                    .put("reason", refundReason)
                    .put("notify_url", refundNotifyUrl);
            rootNode.putObject("amount")
                    .put("total", totalAmount.multiply(new BigDecimal("100")).longValue())
                    .put("currency", "CNY")
                    .put("refund", refundAmount.multiply(new BigDecimal("100")).longValue());
            log.info("微信退款参数:mchid[{}],appid[{}],reason[{}],transaction_id[{}],notify_url[{}],out_trade_no[{}],totalAmount[{}]元,refundAmount[{}]元",
                    merchantId,appid,refundReason,channelOrderNo,refundNotifyUrl,refundNo,totalAmount,refundAmount);
            objectMapper.writeValue(bos, rootNode);

            httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
            HttpResponse response = httpClient.execute(httpPost);
            String bodyAsString = EntityUtils.toString(response.getEntity());
            log.info("微信退款返回结果:{}",bodyAsString);
            JSONObject object = JSONObject.parseObject(bodyAsString);
            int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HttpStatus.OK.value()){
                Map<String,String> map = new HashMap<>();
                String status = object.getString("status");
                if ("SUCCESS".equals(status)){
                    Date success_time = object.getDate("success_time");
                    String refund_id = object.getString("refund_id");
                    String user_received_account = object.getString("user_received_account");
                    String channel = object.getString("channel");
                    map.put("success_time",String.valueOf(success_time.getTime()));
                    map.put("refund_id",refund_id);
                    map.put("channel",channel);
                    map.put("user_received_account",user_received_account);
                    return CommonResult.OK(map);
                }else if ("PROCESSING".equals(status)){
                    String refund_id = object.getString("refund_id");
                    map.put("refund_id",refund_id);
                    CommonResult commonResult = CommonResult.Err();
                    commonResult.setMsg("退款中");
                    commonResult.setObj(map);
                    return commonResult;
                }else if ("ABNORMAL".equals(status)){
                    CommonResult commonResult = CommonResult.Err();
                    commonResult.setMsg("退款异常");
                    commonResult.setObj(map);
                    return commonResult;
                }else{
                    CommonResult commonResult = CommonResult.Err();
                    commonResult.setMsg("退款关闭");
                    commonResult.setObj(map);
                    return commonResult;
                }
            }else {
                return CommonResult.Err(object.getString("message"));
            }
        }catch (Exception e){
            log.error("微信退款异常",e);
            return CommonResult.Err("网络异常");
        }
    }
    /**
     * 验签
     * @param timestamp 微信请求参数中的时间戳
     * @param nonce 微信请求参数中的随机数
     * @param data 微信请求参数中的原数据
     * @param serialNo 证书序列号
     * @param sign 待验证的签名
     * @return
     */
    private Boolean verifySign(String timestamp, String nonce, String data, String serialNo, String sign){
        boolean verifySign = false;
        try {
            String wxpayPubKeyPath = weixinProperties.getPublicKeyPath();
            String signData= timestamp + "\n" +
                    nonce + "\n" +
                    data + "\n";
            String pubKeyPath = wxpayPubKeyPath + serialNo+"_wxp_pub.pem";
            verifySign = WxPayUtil.verifySign(signData, sign, pubKeyPath);
        } catch (Exception e) {
            log.error("微信支付回调通知,验签异常",e);
        }
        log.info("微信支付验签结果 verifySign:{}", verifySign);
        return verifySign;
    }
    /**
     * 解密密文数据
     * @param data 密文数据
     * @param key 解密key
     * @return
     */
    private String decryptData(String data, String key){
        try {
            JSONObject jsonObject = JSONObject.parseObject(data);
            JSONObject resource = jsonObject.getJSONObject("resource");
            String ciphertext = resource.getString("ciphertext");
            String nonce = resource.getString("nonce");
            String associatedData = resource.getString("associated_data");
            String decrypt = AESUtil.decryptToString(associatedData, nonce, ciphertext, key);
            log.info("微信支付解密后的数据:{}", decrypt);
            return decrypt;
        } catch (Exception e) {
            log.error("微信支付回调通知，解密数据异常", e);
        }
        return null;
    }
    /**
     * 验签
     * @param srcData
     * @param publicKey
     * @param sign
     * @return
     * @throws Exception
     */
    public static boolean verify(String srcData, String sign,  PublicKey publicKey) throws Exception {
        byte[] keyBytes = publicKey.getEncoded();
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey key = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(key);
        signature.update(srcData.getBytes());
        return signature.verify(org.apache.commons.codec.binary.Base64.decodeBase64(sign.getBytes()));
    }


    /**
     * 方法描述：企业付款到零钱
     * 创建时间：2017年4月12日  上午11:04:25
     * 作者： xubo
     *
     * @param
     * @param userType
     * @return
     */
    public CommonResult<Map<String,String>> companyTransferPerson(String orderNo, BigDecimal withdrawAmount, String realName, String openId, Integer userType) {
        BaseWeixinProperties properties = weixinProperties.getMiniapp();

        //构建请求参数
        Map<Object, Object> params = buildRequestMapParam(orderNo, withdrawAmount, openId,realName,properties);
        String mapToXml = XmlUtil.convertMap2Xml(params);
        //请求微信
        String responseXml = sendSSLPostToWx(mapToXml, WechatConfig.getSslcsf(weixinProperties.getMchid(),weixinProperties.getCompanyTransferPersonCertName()));
        WechatCompanyTransferPersonApiResult transferPerson = (WechatCompanyTransferPersonApiResult) XmlUtil.xml2Object(responseXml, WechatCompanyTransferPersonApiResult.class);
        log.info("企业付款到零钱返回结果:{}", JSONObject.toJSONString(transferPerson));
        if (null == transferPerson){
            return CommonResult.Err("微信未返回结果");
        }else {
            if (!"SUCCESS".equals(transferPerson.getReturn_code())){
                Map<String,String> resp = new HashMap<>();
                resp.put("returnCode",transferPerson.getReturn_code());
                CommonResult commonResult = CommonResult.Err(transferPerson.getReturn_msg());
                commonResult.setObj(resp);
                return commonResult;
            }else {
                if (!"SUCCESS".equals(transferPerson.getResult_code())){
                    Map<String,String> resp = new HashMap<>();
                    resp.put("returnCode",transferPerson.getErr_code());
                    CommonResult commonResult = CommonResult.Err(transferPerson.getErr_code_des());
                    commonResult.setObj(resp);
                    return commonResult;
                }else {
                    Map<String,String> resp = new HashMap<>();
                    resp.put("outOrderNo",transferPerson.getPayment_no());
                    resp.put("paySuccessTime",transferPerson.getPayment_time());
                    resp.put("returnCode",transferPerson.getResult_code());
                    return CommonResult.OK(resp);
                }
            }
        }
    }

    /**
     * 得到企业付款到零钱的参数
     * @param orderNo 订单号
     * @param amount 提现金额（元）
     * @param openId 用户openid
     * @param realName 用户真实姓名
     * @param properties
     * @return
     */
    private Map<Object, Object> buildRequestMapParam(String orderNo, BigDecimal amount, String openId, String realName, BaseWeixinProperties properties) {
        Map<Object, Object> params = new HashMap<>();
        //微信分配的公众账号ID（企业号corpid即为此appId）
//        BaseWeixinProperties business = weixinProperties.getBusiness();
        params.put("mch_appid",properties.getAppid());
        //微信支付分配的商户号
        params.put("mchid",weixinProperties.getMchid());
        //随机字符串，不长于32位。推荐随机数生成算法
        params.put("nonce_str", UUIDUtils.generateUUID());
        //商户侧传给微信的订单号
        params.put("partner_trade_no", orderNo);
        //商户appid下，某用户的openid
        params.put("openid", openId);
        //校验用户姓名选项 NO_CHECK：不校验真实姓名 FORCE_CHECK：强校验真实姓名
        params.put("check_name", "FORCE_CHECK");
        //收款用户真实姓名。
        //如果check_name设置为FORCE_CHECK，则必填用户真实姓名
        //如需电子回单，需要传入收款用户姓名
        params.put("re_user_name", realName);
        //打款金额，单位为分，只能为整数
        params.put("amount", amount.multiply(new BigDecimal(100)).intValue());
        //企业付款备注
        params.put("desc", "分润提现");
        //签名前必须要参数全部写在前面
        params.put("sign", arraySign(params, weixinProperties.getSignKey()));
        return params;
    }

    /**
     * 请求微信https
     **/
    public String sendSSLPostToWx(String mapToXml, SSLConnectionSocketFactory sslcsf) {
        log.info("*******企业付款到零钱（WX Request：" + mapToXml);
        String companyToPersonPayUrl="https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
        HttpPost httPost = new HttpPost(companyToPersonPayUrl);
        httPost.addHeader("Connection", "keep-alive");
        httPost.addHeader("Accept", "*/*");
        httPost.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        httPost.addHeader("Host", "api.mch.weixin.qq.com");
        httPost.addHeader("X-Requested-With", "XMLHttpRequest");
        httPost.addHeader("Cache-Control", "max-age=0");
        httPost.addHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0) ");
        httPost.setEntity(new StringEntity(mapToXml, "UTF-8"));
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslcsf).build();
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httPost);
            HttpEntity entity = response.getEntity();
            String xmlStr = EntityUtils.toString(entity, "UTF-8");
            log.info("*******企业付款到零钱（WX Response：" + xmlStr);
            return xmlStr;
        } catch (Exception e) {
            log.error("企业付款到零钱", e);
            return null;
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    /**
     * 方法描述：根据签名加密请求参数
     * 创建时间：2017年6月8日  上午11:28:52
     * 作者： xubo
     *
     * @param
     * @return
     */
    public String arraySign(Map<Object, Object> params, String paySignKey) {

        Set<Object> keysSet = params.keySet();
        Object[] keys = keysSet.toArray();
        Arrays.sort(keys);
        StringBuilder temp = new StringBuilder();
        boolean first = true;
        for (Object key : keys) {
            if (first) {
                first = false;
            } else {
                temp.append("&");
            }
            temp.append(key).append("=");
            Object value = params.get(key);
            String valueString = "";
            if (null != value) {
                valueString = value.toString();
            }
            temp.append(valueString);
//            try {
//                temp.append(URLEncoder.encode(valueString, "UTF-8"));
//            } catch (UnsupportedEncodingException e) {
//                e.printStackTrace();
//            }
        }
        temp.append("&key=");
        temp.append(paySignKey);
        log.info("签名串:{}",temp.toString());
        String md5 = MD5.getMD5(temp.toString());
        log.info("签名结果:{}",md5);
        return md5;
    }

    /**
     * 私钥签名
     *
     * @param data       需要加密的数据
     * @param privateKey 私钥
     * @return 加密后的数据
     * @throws Exception 异常信息
     */
    public static String encryptByPrivateKey(String data, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256WithRSA");
        signature.initSign(privateKey);
        signature.update(data.getBytes(StandardCharsets.UTF_8));
        byte[] signed = signature.sign();
        return Base64.getEncoder().encodeToString(signed);
    }

//    public static void main(String[] args) {
//        WeChatUtil weChatUtil = new WeChatUtil();
//        String data="xWmUknP9jLHq9x9LpVcxlv3KQEfS+juvRvCQQg/0LMrgdR1fHPIN3MWScIKTXg/6xOcL+xMl5JTPmo6Xi+zT3gz38pG+mC/8toFvxBAsRLJe6wY+7r1K2CZHWTo7rVoDvNJahtiqRvmxkh9XoRePJ75C8JeJIp+5ehJy9wQ4k1j6hGFBzizZ6iDGZUYQrcltGRi3OWBBRpU7bSewvR5fPUCI/+ZRwhcIajhZZVIwMa3FGSgFeykrz5VR+KyhYp0Z9Vu1tlNDnzxOCRxFbJwfjJk5BdNe48m6fqIxuRTVNXqz5xutzG9mxNwZT5Ze/PNoQECx1otU8f8YdNuXrQakkSxxXEFf8dUL/CvoobnhXHLoe2lgT6sI0tybOt/KEu78NvpTf60of9sn9ETEYxjTXvmuV3UQvqrC32nXRcg2XAHiHiX8VIbSIzpSavtyv1TAckhto24fYNwoUCJXyFxc2JTSgRpKCEpIuVispac266f3qRxNKT0LzIw69r0GBM58YvGQfrJCuXalJpoUgKZEu9hh8b+wMcvYDz8/BLYn/UZJb1xSZ71gZNShNkJJtDIJ0Sp2";
//        String timestamp="1640254789";
//        String wxSignature="Rw4sQUK88nmO4Xzbe/QDPSdCqT3W+c2Fh+cxedzZA+I1rfTK2goU6zSEmgdqoIqlUMcIlTNBCQsECAt2jzjuFGBI0upRVJ5Oc+gJ0/LIp0vAeIsbqU2jKPdrdpi+ahoIy+Ae5oYBQBhKJIUwrK24euiZ6JJJOFyJ0FiFIgTjzvYhYmKu/4RWByfX4VtWESs2qhveqWLI9AZXlLBi4XFW20QIro2sdx672g1wAiqEUYzilP+vKs8Wt2BQwhx/vsJxLlTn1VwQp5ZXkusOTn9TcV3i8Uf0CwtnaE0P4fz5Ee3Z30UwflQu1Qwqx6y5rciwHMOcPUmMhCdoRO1hQaJVVQ==";
//        String serial="451C0523505DC939BB89BB5A4DE51A73412795DD";
//        String headerNonce="F9TQtyHvwXNQPE09siJt5soBK80e92rG";
//        Boolean aBoolean = weChatUtil.verifySign(timestamp, headerNonce, data, serial, wxSignature);
//        System.out.println(aBoolean);
//    }
}
